<!DOCTYPE html>
<html>

<head>
  <title>从零开始学webpack「v5.0」</title>
  <meta charset='utf-8'>
  <link href='https://cdn.maxiang.io/res-min/themes/marxico.css' rel='stylesheet'>
  <style>
    #preview-contents {
      margin-top: -20px;
      width: 1000px;
    }
  </style>
</head>

<body>
  <div id='preview-contents' class='note-content'>
    <h3 id="从零开始学webpackv50">从零开始学webpack「v5.0」</h3>
    <blockquote>
      <p><a href="https://webpack.docschina.org/" target="_blank">https://webpack.docschina.org/</a> <br>
        webpack是一个现代JavaScript应用程序的静态模块打包工具。当webpack处理应用程序时，它会在内部构建一个依赖图(dependency [/dɪˈpendənsi/] graph
        [/ɡræf/])，此依赖图会映射项目所需的每个模块，并生成一个或多个bundle /ˈbʌndl/ 包！</p>
    </blockquote>

    <h4 id="为啥要学webpack">为啥要学webpack？</h4>
    <p>之前我们在讲前端性能优化的时候，我们可以从以下几个方面，去提高页面第一次渲染的速度，以及运行时的性能：</p>
    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-comment">/* </span>
</div><div class="hljs-line"><span class="hljs-comment">第一类：明显改善页面第一次加载的速度，减少白屏等待的时间</span>
</div><div class="hljs-line"><span class="hljs-comment">    @1 使用骨架屏技术</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 服务器骨架屏：页面首屏内容是基于服务器渲染的</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 前端骨架屏：在真实内容渲染出来之前，我们给予相关位置用“色框”占位！</span>
</div><div class="hljs-line"><span class="hljs-comment">    @2 减少HTTP请求的次数和大小</span>
</div><div class="hljs-line"><span class="hljs-comment">     + CSS/JS都要做合并压缩「尽可能合并为一个CSS和一个JS」</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 图片的合并压缩，例如：雪碧图(CSS Sprit)</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 使用图片BASE64来加快图片的渲染！</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 图片一定要做延迟加载</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 使用字体图片和矢量图，来代替位图！！</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 音视频资源也要设置延迟加载「preload='none'」</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 数据的异步加载</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 开启服务器端的GZIP压缩，可以让访问的资源压缩60%+</span>
</div><div class="hljs-line"><span class="hljs-comment">    @3 渲染页面中的优化</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 因为&lt;script&gt;会阻碍GUI渲染，所以：把其放在页面末尾，或者设置async/defer！</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 因为&lt;link&gt;是异步加载CSS资源，所以建议放在页面开始，尽快获取样式资源！！</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 不要使用import导入CSS，因为其会阻碍GUI的渲染！</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 样式代码较少的情况下，使用&lt;style&gt;内嵌式，尤其是移动端开发！</span>
</div><div class="hljs-line"><span class="hljs-comment">    @4 在网络传输中的优化</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 减少cookie的内容大小「因为只要向服务器发送请求，不论服务器是否需要，总会在请求头中把cookie传递给服务器，如果cookie比较大，会让所有的请求都变慢」</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 资源分服务器部署「例如：web服务器、图片服务器、数据服务器」，这样可以降低服务器压力，提高服务器的并发，让资源能更加合理的被利用；但是也会导致DNS解析次数增加，此时可以基于DNS Prefetch来优化DNS解析！！</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 基于HTTP/2.0来代替HTTP/1.1</span>
</div><div class="hljs-line"><span class="hljs-comment">       + 基于新的二进制格式，让传输的内容更加丰富健壮</span>
</div><div class="hljs-line"><span class="hljs-comment">       + header压缩，让传输速度更快</span>
</div><div class="hljs-line"><span class="hljs-comment">       + 服务端推送，可以减少HTTP请求次数</span>
</div><div class="hljs-line"><span class="hljs-comment">       + 多路复用，让传输速度更快，避免线头阻塞</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 基于Connection:keep-alive保持TCP通道长链接「HTTP/1.1版本会自动开启」</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 开启CDN「地域分布式服务器部署」</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 对于静态资源文件采取“强缓存和协商缓存”，对于不经常更新的数据请求，设置数据缓存！</span>
</div><div class="hljs-line"><span class="hljs-comment">     + </span>
</div><div class="hljs-line"><span class="hljs-comment">第二类：提高页面运行时候的性能</span>
</div><div class="hljs-line"><span class="hljs-comment">    @1 减少循环嵌套，降低时间复杂度；避免出现死循环/死递归；</span>
</div><div class="hljs-line"><span class="hljs-comment">    @2 使用事件委托来优化事件绑定，性能可以提高40%+</span>
</div><div class="hljs-line"><span class="hljs-comment">    @3 减少DOM的回流(重排)和重绘</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 样式分离读写「渲染队列机制」</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 批量新增元素「字符串拼接、文档碎片」</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 基于transform/opacity等方式操作样式</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 把需要频繁修改样式的元素(例如：JS实现动画)脱离文档流</span>
</div><div class="hljs-line"><span class="hljs-comment">     + ...</span>
</div><div class="hljs-line"><span class="hljs-comment">    @4 使用函数的防抖和节流处理高频触发操作</span>
</div><div class="hljs-line"><span class="hljs-comment">    @5 合理使用闭包，避免内存泄漏，以及手动释放无用的内存！</span>
</div><div class="hljs-line"><span class="hljs-comment">    @6 减少页面冗余代码，提高代码的重复使用率「也就是尽可能的做封装处理」</span>
</div><div class="hljs-line"><span class="hljs-comment">    @7 尽可能不要使用for/in循环，因为其消耗性能</span>
</div><div class="hljs-line"><span class="hljs-comment">    @8 避免使用eval/with等消耗性能的代码</span>
</div><div class="hljs-line"><span class="hljs-comment">    @9 能用CSS3处理的动画坚决不用JS「JS动画尽可能基于requestAnimationFrame来代替定时器」</span>
</div><div class="hljs-line"><span class="hljs-comment">    @10 避免使用CSS表达式，因为其非常消耗性能</span>
</div><div class="hljs-line"><span class="hljs-comment">    @11 CSS选择器的前缀不要过长「因为CSS选择器渲染是从右到左」</span>
</div><div class="hljs-line"><span class="hljs-comment">    @12 减少table布局「table的渲染是比较消耗性能的」</span>
</div><div class="hljs-line"><span class="hljs-comment">......</span>
</div><div class="hljs-line"><span class="hljs-comment">*/</span>
</div></code></pre>
    <p>
      我们平时开发的时候，一般会使用less/sass/stylus等CSS预编译器「需要基于vscode插件把其编译为CSS」；会直接使用ES6的语法「需要基于babel把其转换为ES5，以此兼容IE」；会给CSS3样式加很多的前缀，以此来处理兼容问题……
      <br>
      我们还会基于vscode中的liveserver插件，创建一个本地web服务器，来预览我们的项目….. <br>
      我们还要基于各种方案，来解决跨域访问的问题……
    </p>
    <hr>
    <p>以上所有内容，如果都需要开发者手动去处理，那么…..也就没有那么了！！</p>
    <p><img longdesc="./1668774490745.png" alt="Alt text" title="" type="image/png" width="200"
        src=""
        class=""></p>
    <p><strong>webpack可以帮我们干的事情：</strong></p>
    <ul>
      <li>
        <p>代码转换：TypeScript编译成JavaScript、LESS/SCSS编译成CSS、ES6/7编译为ES5、虚拟DOM编译为真实的DOM等等…</p>
      </li>
      <li>
        <p>文件优化：压缩JS、CSS、HTML代码，压缩合并图片，图片BASE64等</p>
      </li>
      <li>
        <p>代码分割：提取多个页面的公共代码、提取首屏不需要执行部分的代码等</p>
      </li>
      <li>
        <p>模块合并：把模块分类合并成一个文件</p>
      </li>
      <li>
        <p>自动刷新：创建本地Web服务器，监听本地源代码的变化，自动重新构建，刷新浏览器</p>
      </li>
      <li>
        <p>代码校验：Eslint代码规范校验和检测、单元测试等</p>
      </li>
      <li>
        <p>自动发布：自动构建出线上发布代码并传输给发布系统</p>
      </li>
      <li>
        <p>跨域处理</p>
      </li>
      <li>
        <p>……</p>
      </li>
    </ul>
    <p><strong>除了webpack外，它们也可以做这些事情：</strong></p>
    <ul>
      <li>
        <p>grunt</p>
      </li>
      <li>
        <p>gulp</p>
      </li>
      <li>
        <p>Parcel</p>
      </li>
      <li>
        <p>vite</p>
      </li>
      <li>
        <p>rollup</p>
      </li>
      <li>
        <p>Turbopack</p>
      </li>
      <li>
        <p>......</p>
      </li>
    </ul>

    <hr>

    <h4 id="1-commonjs规范-es6module规范">1. CommonJS规范 &amp; ES6Module规范</h4>
    <blockquote>
      <p>未来的项目一定是 模块化/组件化 开发！！</p>
      <p>模块化编程进化历史</p>
      <ul>
        <li>
          <p>单例设计模式</p>
        </li>
        <li>
          <p>AMD「require.js」</p>
        </li>
        <li>
          <p>CommonJS</p>
        </li>
        <li>
          <p>CMD「sea.js」</p>
        </li>
        <li>
          <p>ES6Module</p>
        </li>
      </ul>
    </blockquote>
    <p><strong>单例设计模式</strong> <br>
      解决问题：模块间相互冲突的问题「闭包」 ; 模块间相互引用的问题; <br>
      不足之处：需要手动分析模块之间的依赖关系，按顺序依次导入相关模块；所有模块都是基于script一个个导入的，这样页面HTTP请求变多！</p>
    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">let</span> xxxModule = (<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
</div><div class="hljs-line">   <span class="hljs-keyword">let</span> time = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>();
</div><div class="hljs-line">   <span class="hljs-keyword">const</span> query = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">query</span>(<span class="hljs-params"></span>) </span>{
</div><div class="hljs-line">       <span class="hljs-comment">// ...</span>
</div><div class="hljs-line">   };
</div><div class="hljs-line">   <span class="hljs-keyword">const</span> handle = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handle</span>(<span class="hljs-params"></span>) </span>{
</div><div class="hljs-line">       <span class="hljs-comment">// ...</span>
</div><div class="hljs-line">   };
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">   <span class="hljs-comment">// 把供其它板块调用的方法，暴露到全局对象上</span>
</div><div class="hljs-line">   <span class="hljs-comment">//「局限：暴露的内容比较多，则还会引发全局变量冲突」</span>
</div><div class="hljs-line">   <span class="hljs-comment">// window.query = query;</span>
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">   <span class="hljs-keyword">return</span> {
</div><div class="hljs-line">       query,
</div><div class="hljs-line">       handle
</div><div class="hljs-line">   };
</div><div class="hljs-line">})();
</div></code></pre>
    <p><strong>AMD「require.js」</strong> <a href="https://requirejs.org" target="_blank">https://requirejs.org</a> <br>
      优势：在保证模块之间独立和可以相互访问的基础上，HTML中无需再导入各个模块了「不存在顺序问题」，也不需要自己去分析相互间的依赖关系！ <br>
      不足：依赖模块的导入是“前置导入”，只有把依赖模块动态导入完毕，才会触发回调函数执行「阻碍代码执行速度」；代码书写的顺序也不是很方便；可能存在重复导入；</p>
    <p><img longdesc="./1668775261198.png" alt="Alt text" title="" type="image/png"
        src=""
        class=""></p>
    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-comment">//main.js</span>
</div><div class="hljs-line"><span class="hljs-built_in">require</span>.config({
</div><div class="hljs-line">    <span class="hljs-comment">//全局配置</span>
</div><div class="hljs-line">    baseUrl: <span class="hljs-string">'js/lib'</span>,
</div><div class="hljs-line">});
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-built_in">require</span>([<span class="hljs-string">'moduleB'</span>, <span class="hljs-string">'moduleA'</span>], <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">moduleB, moduleA</span>) </span>{
</div><div class="hljs-line">    <span class="hljs-built_in">console</span>.log(moduleB.average(<span class="hljs-number">10</span>, <span class="hljs-number">20</span>, <span class="hljs-number">30</span>, <span class="hljs-number">40</span>, <span class="hljs-number">50</span>));
</div><div class="hljs-line">});
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-comment">//moduleA.js</span>
</div><div class="hljs-line">define(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> {
</div><div class="hljs-line">        sum(...args) {
</div><div class="hljs-line">            <span class="hljs-keyword">let</span> len = args.length,
</div><div class="hljs-line">                firstItem = args[<span class="hljs-number">0</span>];
</div><div class="hljs-line">            <span class="hljs-keyword">if</span> (len === <span class="hljs-number">0</span>) <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
</div><div class="hljs-line">            <span class="hljs-keyword">if</span> (len === <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> firstItem;
</div><div class="hljs-line">            <span class="hljs-keyword">return</span> args.reduce(<span class="hljs-function">(<span class="hljs-params">total, item</span>) =&gt;</span> {
</div><div class="hljs-line">                <span class="hljs-keyword">return</span> total + item;
</div><div class="hljs-line">            });
</div><div class="hljs-line">        }
</div><div class="hljs-line">    };
</div><div class="hljs-line">});
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-comment">//moduleB.js</span>
</div><div class="hljs-line">define([<span class="hljs-string">'moduleA'</span>], <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">moudleA</span>) </span>{
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> {
</div><div class="hljs-line">        <span class="hljs-comment">// 求平均数（去掉最大最小值）</span>
</div><div class="hljs-line">        average(...args) {
</div><div class="hljs-line">            <span class="hljs-keyword">let</span> len = args.length,
</div><div class="hljs-line">                firstItem = args[<span class="hljs-number">0</span>];
</div><div class="hljs-line">            <span class="hljs-keyword">if</span> (len === <span class="hljs-number">0</span>) <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
</div><div class="hljs-line">            <span class="hljs-keyword">if</span> (len === <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> firstItem;
</div><div class="hljs-line">            args.sort(<span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> a - b);
</div><div class="hljs-line">            args.pop();
</div><div class="hljs-line">            args.shift();
</div><div class="hljs-line">            <span class="hljs-keyword">return</span> (moudleA.sum(...args) / args.length).toFixed(<span class="hljs-number">2</span>);
</div><div class="hljs-line">        }
</div><div class="hljs-line">    };
</div><div class="hljs-line">});
</div></code></pre>
    <p><strong>CommonJS模块化规范</strong> <br>
      唯一的问题：浏览器端不支持CommonJS规范 <br>
      淘宝“玉伯”仿照CommonJS规范，研发了一款插件 sea.js ，旨在把CommonJS规范搬到浏览器端运行「这种模块思想被称之为CMD」</p>
    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-comment">/* ---A.js--- */</span>
</div><div class="hljs-line"><span class="hljs-keyword">const</span> sum = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sum</span>(<span class="hljs-params">...params</span>) </span>{
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> params.reduce(<span class="hljs-function">(<span class="hljs-params">result, item</span>) =&gt;</span> {
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> result + item;
</div><div class="hljs-line">    });
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-comment">// 暴露一些API</span>
</div><div class="hljs-line"><span class="hljs-built_in">module</span>.exports = {
</div><div class="hljs-line">    sum
</div><div class="hljs-line">};
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-comment">/* ---B.js--- */</span>
</div><div class="hljs-line"><span class="hljs-keyword">let</span> name = <span class="hljs-string">'哈哈'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">let</span> A = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./A'</span>);
</div><div class="hljs-line"><span class="hljs-keyword">const</span> average = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">average</span>(<span class="hljs-params">...params</span>) </span>{
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> (A.sum(...params) / params.length).toFixed(<span class="hljs-number">2</span>);
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-built_in">module</span>.exports = {
</div><div class="hljs-line">    average
</div><div class="hljs-line">};
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-comment">/* ---main.js--- */</span>
</div><div class="hljs-line"><span class="hljs-keyword">let</span> A = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./A'</span>);
</div><div class="hljs-line"><span class="hljs-built_in">console</span>.log(A.sum(<span class="hljs-number">10</span>, <span class="hljs-number">20</span>, <span class="hljs-number">30</span>, <span class="hljs-number">40</span>));
</div><div class="hljs-line"><span class="hljs-keyword">let</span> B = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./B'</span>);
</div><div class="hljs-line"><span class="hljs-built_in">console</span>.log(B.average(<span class="hljs-number">10</span>, <span class="hljs-number">20</span>, <span class="hljs-number">30</span>, <span class="hljs-number">40</span>));
</div></code></pre>
    <p><strong>ES6Module模块规范</strong> <br>
      <a href="https://es6.ruanyifeng.com/#docs/module" target="_blank">https://es6.ruanyifeng.com/#docs/module</a> <br>
      可以直接运行在浏览器端；不支持IE；
    </p>
    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-comment">/* </span>
</div><div class="hljs-line"><span class="hljs-comment">模块的导入导出:</span>
</div><div class="hljs-line"><span class="hljs-comment">  整体来讲，每个模块导出的是一个Module对象，我们可以基于 export/export default 为对象中加入导出的内容</span>
</div><div class="hljs-line"><span class="hljs-comment">    @1 export default xxx;</span>
</div><div class="hljs-line"><span class="hljs-comment">      + xxx可以是任意类型值</span>
</div><div class="hljs-line"><span class="hljs-comment">      + 给Module对象新增一个 “default” 属性，属性值就是导出的值</span>
</div><div class="hljs-line"><span class="hljs-comment">      + 在一个模块中，export default只允许出现一次</span>
</div><div class="hljs-line"><span class="hljs-comment">    @2 export 创建值的表达式（声明变量 = 值）;</span>
</div><div class="hljs-line"><span class="hljs-comment">      let num = 10;</span>
</div><div class="hljs-line"><span class="hljs-comment">      export num; //这样写是错误的</span>
</div><div class="hljs-line"><span class="hljs-comment">      export let num = 10; //这样写是正确的</span>
</div><div class="hljs-line"><span class="hljs-comment">      ---</span>
</div><div class="hljs-line"><span class="hljs-comment">      let num = 10;</span>
</div><div class="hljs-line"><span class="hljs-comment">      export {</span>
</div><div class="hljs-line"><span class="hljs-comment">        num, //这样写是可以的</span>
</div><div class="hljs-line"><span class="hljs-comment">        x:100 //这样写是错误的</span>
</div><div class="hljs-line"><span class="hljs-comment">      };</span>
</div><div class="hljs-line"><span class="hljs-comment">      ---</span>
</div><div class="hljs-line"><span class="hljs-comment">      + export可以出现多次，导出多个内容</span>
</div><div class="hljs-line"><span class="hljs-comment">      + 声明的变量叫啥名字，最后给Module对象加入的是同名的属性名，属性值就是变量的值</span>
</div><div class="hljs-line"><span class="hljs-comment"></span>
</div><div class="hljs-line"><span class="hljs-comment">  我们会基于 import 方法导入模块「导入模块导出的内容」</span>
</div><div class="hljs-line"><span class="hljs-comment">    @1 import N from '模块地址(在浏览器端不能忽略.js后缀名)';</span>
</div><div class="hljs-line"><span class="hljs-comment">     + N获取的不是整个导出的Module对象，仅仅获取的是Module中default这一项的值</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 不能在import期间，直接对N解构赋值，因为涉及解构赋值就会变为另外一种情况</span>
</div><div class="hljs-line"><span class="hljs-comment">    @2 import {x,y} from '模块地址';</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 直接对导出的Module对象中(排除default属性)，导出的内容进行解构赋值</span>
</div><div class="hljs-line"><span class="hljs-comment">    @3 import * as M from '模块地址';</span>
</div><div class="hljs-line"><span class="hljs-comment">     + 先导入所有导出的内容，赋值给M变量</span>
</div><div class="hljs-line"><span class="hljs-comment">*/</span>
</div></code></pre>

    <hr>

    <h4 id="2webpack的基础操作">2.webpack的基础操作</h4>
    <p><strong>安装</strong></p>
    <pre class="prettyprint hljs-dark"><code class="hljs stata"><div class="hljs-line"><span class="hljs-comment">// 为防止全局安装webpack导致版本冲突，真实项目中以本地安装为主 </span>
</div><div class="hljs-line">$ npm init -<span class="hljs-built_in">y</span>
</div><div class="hljs-line">$ npm install webpack webpack-<span class="hljs-keyword">cli</span> --<span class="hljs-keyword">save</span>-dev
</div><div class="hljs-line">OR
</div><div class="hljs-line">$ yarn add webpack webpack-<span class="hljs-keyword">cli</span> -<span class="hljs-built_in">D</span>
</div></code></pre>

    <p><strong>零配置使用</strong></p>
    <pre class="prettyprint hljs-dark"><code class="hljs gams"><div class="hljs-line"><span class="hljs-comment">/*</span>
</div><div class="hljs-line"><span class="hljs-comment"> * 默认会打包SRC目录中的JS文件（入口默认index.js）</span>
</div><div class="hljs-line"><span class="hljs-comment"> * 打包完成的目录默认是DIST/MAIN.JS</span>
</div><div class="hljs-line"><span class="hljs-comment"> * webpack默认支持CommonJS和ES6 Module的模块规范，依此进行依赖打包</span>
</div><div class="hljs-line"><span class="hljs-comment"> */</span>
</div><div class="hljs-line"><span class="hljs-symbol">$</span> npx webpack
</div></code></pre>

    <p><strong>自定义基础配置</strong></p>

    <blockquote>
      <p>webpack.config.js</p>
    </blockquote>

    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-comment">// Node内置的路径处理模块</span>
</div><div class="hljs-line"><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>);
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-comment">// 导出自定义配置项</span>
</div><div class="hljs-line"><span class="hljs-built_in">module</span>.exports = {
</div><div class="hljs-line">    <span class="hljs-comment">// 环境模式「生产环境：production   开发环境：development」</span>
</div><div class="hljs-line">    mode: <span class="hljs-string">'production'</span>,
</div><div class="hljs-line">    <span class="hljs-comment">// 打包入口「相对路径」</span>
</div><div class="hljs-line">    entry: <span class="hljs-string">'./src/index.js'</span>,
</div><div class="hljs-line">    <span class="hljs-comment">// 打包出口</span>
</div><div class="hljs-line">    output: {
</div><div class="hljs-line">        <span class="hljs-comment">// 生成的文件名. [hash]创建随机哈希值</span>
</div><div class="hljs-line">        filename: <span class="hljs-string">'bundle.[hash].js'</span>,
</div><div class="hljs-line">        <span class="hljs-comment">// 打包地址「绝对路径」</span>
</div><div class="hljs-line">        path: path.resolve(__dirname, <span class="hljs-string">'dist'</span>)
</div><div class="hljs-line">    }
</div><div class="hljs-line">};
</div></code></pre>

    <p><strong>html-webpack-plugin</strong></p>

    <blockquote>
      <p><a href="https://www.webpackjs.com/plugins/html-webpack-plugin/"
          target="_blank">https://www.webpackjs.com/plugins/html-webpack-plugin/</a> <br>
        $ yarn add html-webpack-plugin -D</p>
    </blockquote>

    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">const</span> HtmlWebpackPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'html-webpack-plugin'</span>);
</div><div class="hljs-line"><span class="hljs-built_in">module</span>.exports = {
</div><div class="hljs-line">    ...
</div><div class="hljs-line">    plugins: [
</div><div class="hljs-line">        <span class="hljs-keyword">new</span> HtmlWebpackPlugin({
</div><div class="hljs-line">            <span class="hljs-comment">// 指定视图模板</span>
</div><div class="hljs-line">            template: <span class="hljs-string">'./public/index.html'</span>,
</div><div class="hljs-line">            <span class="hljs-comment">// 编译后视图的名字</span>
</div><div class="hljs-line">            filename: <span class="hljs-string">'index.html'</span>,
</div><div class="hljs-line">            <span class="hljs-comment">// 是否压缩</span>
</div><div class="hljs-line">            minify: <span class="hljs-literal">true</span>
</div><div class="hljs-line">        })
</div><div class="hljs-line">    ]
</div><div class="hljs-line">}
</div></code></pre>

    <p><strong>多入口 &amp; 多出口</strong></p>



    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">const</span> HtmlWebpackPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'html-webpack-plugin'</span>);
</div><div class="hljs-line"><span class="hljs-comment">// HtmlWebpackPlugin需要配置多套</span>
</div><div class="hljs-line"><span class="hljs-keyword">const</span> htmlPlugins = [<span class="hljs-string">'index'</span>, <span class="hljs-string">'login'</span>].map(<span class="hljs-function"><span class="hljs-params">chunk</span> =&gt;</span> {
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> HtmlWebpackPlugin({
</div><div class="hljs-line">        <span class="hljs-attr">template</span>: <span class="hljs-string">`./public/<span class="hljs-subst">${chunk}</span>.html`</span>,
</div><div class="hljs-line">        <span class="hljs-attr">filename</span>: <span class="hljs-string">`<span class="hljs-subst">${chunk}</span>.html`</span>,
</div><div class="hljs-line">        <span class="hljs-comment">// 指定导入的JS</span>
</div><div class="hljs-line">        chunks: [chunk],
</div><div class="hljs-line">        <span class="hljs-attr">minify</span>: <span class="hljs-literal">true</span>
</div><div class="hljs-line">    });
</div><div class="hljs-line">});
</div><div class="hljs-line"><span class="hljs-built_in">module</span>.exports = {
</div><div class="hljs-line">    <span class="hljs-attr">mode</span>: <span class="hljs-string">'production'</span>,
</div><div class="hljs-line">    <span class="hljs-comment">// 配置多入口</span>
</div><div class="hljs-line">    entry: {
</div><div class="hljs-line">        <span class="hljs-attr">index</span>: <span class="hljs-string">"./src/index.js"</span>,
</div><div class="hljs-line">        <span class="hljs-attr">login</span>: <span class="hljs-string">"./src/login.js"</span>,
</div><div class="hljs-line">    },
</div><div class="hljs-line">    <span class="hljs-comment">// 出口采用相同的规则</span>
</div><div class="hljs-line">    output: {
</div><div class="hljs-line">        <span class="hljs-attr">filename</span>: <span class="hljs-string">"[name].[hash].js"</span>,
</div><div class="hljs-line">        <span class="hljs-attr">path</span>: path.resolve(__dirname, <span class="hljs-string">"dist"</span>)
</div><div class="hljs-line">    },
</div><div class="hljs-line">    <span class="hljs-attr">plugins</span>: [
</div><div class="hljs-line">        ...htmlPlugins
</div><div class="hljs-line">    ]
</div><div class="hljs-line">};
</div></code></pre>

    <p><strong>clean-webpack-plugin</strong></p>

    <blockquote>
      <p>$ yarn add clean-webpack-plugin -D</p>
    </blockquote>



    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">const</span> { CleanWebpackPlugin } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'clean-webpack-plugin'</span>);
</div><div class="hljs-line"><span class="hljs-built_in">module</span>.exports = {
</div><div class="hljs-line">    ...
</div><div class="hljs-line">    plugins: [
</div><div class="hljs-line">        <span class="hljs-keyword">new</span> CleanWebpackPlugin()
</div><div class="hljs-line">    ]
</div><div class="hljs-line">};
</div></code></pre>

    <p><strong>webpack-dev-server</strong></p>

    <blockquote>
      <p><a href="https://webpack.js.org/configuration/dev-server/"
          target="_blank">https://webpack.js.org/configuration/dev-server/</a> <br>
        $ yarn add webpack-dev-server -D</p>
    </blockquote>



    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-comment">/* paclage.json */</span>
</div><div class="hljs-line"><span class="hljs-string">"scripts"</span>: {
</div><div class="hljs-line">   <span class="hljs-string">"start"</span>: <span class="hljs-string">"webpack server"</span>,
</div><div class="hljs-line">   <span class="hljs-string">"build"</span>: <span class="hljs-string">"webpack"</span>
</div><div class="hljs-line">}
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-comment">/* webpack.config.js */</span>
</div><div class="hljs-line"><span class="hljs-built_in">module</span>.exports = {
</div><div class="hljs-line">    ... 
</div><div class="hljs-line">    devServer: {
</div><div class="hljs-line">        <span class="hljs-comment">// 域名</span>
</div><div class="hljs-line">        host: <span class="hljs-string">'127.0.0.1'</span>,
</div><div class="hljs-line">        <span class="hljs-comment">// 断口号</span>
</div><div class="hljs-line">        port: <span class="hljs-number">3000</span>,
</div><div class="hljs-line">        <span class="hljs-comment">// GZIP压缩</span>
</div><div class="hljs-line">        compress: <span class="hljs-literal">true</span>,
</div><div class="hljs-line">        <span class="hljs-comment">// 自动打开浏览器</span>
</div><div class="hljs-line">        open: <span class="hljs-literal">true</span>,
</div><div class="hljs-line">        <span class="hljs-comment">// 热更新</span>
</div><div class="hljs-line">        hot: <span class="hljs-literal">true</span>,
</div><div class="hljs-line">        <span class="hljs-comment">// 跨域代理</span>
</div><div class="hljs-line">        proxy: {
</div><div class="hljs-line">            <span class="hljs-string">"/jian"</span>: {
</div><div class="hljs-line">                <span class="hljs-attr">target</span>: <span class="hljs-string">"https://www.jianshu.com/asimov"</span>,
</div><div class="hljs-line">                <span class="hljs-attr">changeOrigin</span>: <span class="hljs-literal">true</span>,
</div><div class="hljs-line">                <span class="hljs-attr">ws</span>: <span class="hljs-literal">true</span>,
</div><div class="hljs-line">                <span class="hljs-attr">pathRewrite</span>: { <span class="hljs-string">"^/jian"</span>: <span class="hljs-string">""</span> }
</div><div class="hljs-line">            },
</div><div class="hljs-line">            <span class="hljs-string">"/zhi"</span>: {
</div><div class="hljs-line">                <span class="hljs-attr">target</span>: <span class="hljs-string">"https://news-at.zhihu.com/api/4"</span>,
</div><div class="hljs-line">                <span class="hljs-attr">changeOrigin</span>: <span class="hljs-literal">true</span>,
</div><div class="hljs-line">                <span class="hljs-attr">ws</span>: <span class="hljs-literal">true</span>,
</div><div class="hljs-line">                <span class="hljs-attr">pathRewrite</span>: { <span class="hljs-string">"^/zhi"</span>: <span class="hljs-string">""</span> }
</div><div class="hljs-line">            }
</div><div class="hljs-line">        }
</div><div class="hljs-line">    }
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-comment">/* </span>
</div><div class="hljs-line"><span class="hljs-comment">测试接口 </span>
</div><div class="hljs-line"><span class="hljs-comment">  简书：</span>
</div><div class="hljs-line"><span class="hljs-comment">  https://www.jianshu.com/asimov/subscriptions/recommended_collections</span>
</div><div class="hljs-line"><span class="hljs-comment">  知乎：</span>
</div><div class="hljs-line"><span class="hljs-comment">  https://news-at.zhihu.com/api/4/news/latest</span>
</div><div class="hljs-line"><span class="hljs-comment">*/</span>
</div></code></pre>

    <p><strong>处理样式的loader「加载器」</strong></p>

    <blockquote>
      <p>$ yarn add css-loader style-loader less less-loader autoprefixer postcss-loader -D</p>
    </blockquote>

    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-built_in">module</span>.exports = {
</div><div class="hljs-line">    ...
</div><div class="hljs-line">    <span class="hljs-comment">/* 配置模块加载器LOADER，执行顺序：从右向左、从下向上 */</span>
</div><div class="hljs-line">    <span class="hljs-built_in">module</span>: {
</div><div class="hljs-line">        <span class="hljs-attr">rules</span>: [{
</div><div class="hljs-line">            <span class="hljs-attr">test</span>: <span class="hljs-regexp">/\.(css|less)$/</span>, <span class="hljs-comment">// 基于正则匹配哪些模块需要处理</span>
</div><div class="hljs-line">            use: [
</div><div class="hljs-line">                <span class="hljs-string">"style-loader"</span>, <span class="hljs-comment">// 把CSS插入到HEAD中</span>
</div><div class="hljs-line">                <span class="hljs-string">"css-loader"</span>, <span class="hljs-comment">// 编译解析@import/URL()这种语法</span>
</div><div class="hljs-line">                <span class="hljs-string">"postcss-loader"</span>, <span class="hljs-comment">// 设置前缀</span>
</div><div class="hljs-line">                <span class="hljs-string">"less-loader"</span> <span class="hljs-comment">// 把LESS编译为CSS</span>
</div><div class="hljs-line">            ]
</div><div class="hljs-line">        }]
</div><div class="hljs-line">    }
</div><div class="hljs-line">};
</div></code></pre>

    <p>postcss.config.js</p>



    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-built_in">module</span>.exports = {
</div><div class="hljs-line">    <span class="hljs-attr">plugins</span>: [
</div><div class="hljs-line">        <span class="hljs-built_in">require</span>(<span class="hljs-string">'autoprefixer'</span>)
</div><div class="hljs-line">    ]
</div><div class="hljs-line">};
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line"><span class="hljs-comment">// 或者在配置项中直接处理</span>
</div><div class="hljs-line">{
</div><div class="hljs-line">    <span class="hljs-attr">loader</span>: <span class="hljs-string">"postcss-loader"</span>,
</div><div class="hljs-line">    <span class="hljs-attr">options</span>: {
</div><div class="hljs-line">        <span class="hljs-attr">postcssOptions</span>: {
</div><div class="hljs-line">            <span class="hljs-attr">plugins</span>: [
</div><div class="hljs-line">                <span class="hljs-built_in">require</span>(<span class="hljs-string">'autoprefixer'</span>)
</div><div class="hljs-line">            ]
</div><div class="hljs-line">        }
</div><div class="hljs-line">    }
</div><div class="hljs-line">},
</div></code></pre>

    <p>package.json OR .browserslistrc</p>

    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-comment">// https://github.com/browserslist/browserslist</span>
</div><div class="hljs-line"><span class="hljs-string">"browserslist"</span>: [
</div><div class="hljs-line">  <span class="hljs-string">"&gt; 1%"</span>,
</div><div class="hljs-line">  <span class="hljs-string">"last 2 versions"</span>,
</div><div class="hljs-line">  <span class="hljs-string">"not dead"</span>
</div><div class="hljs-line">]
</div></code></pre>

    <p><strong>mini-css-extract-plugin 抽离CSS样式</strong> /ˈekstrækt/</p>

    <blockquote>
      <p><a href="https://www.npmjs.com/package/mini-css-extract-plugin"
          target="_blank">https://www.npmjs.com/package/mini-css-extract-plugin</a> <br>
        $ yarn add mini-css-extract-plugin -D</p>
    </blockquote>



    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">const</span> MiniCssExtractPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mini-css-extract-plugin'</span>);
</div><div class="hljs-line"><span class="hljs-built_in">module</span>.exports = {
</div><div class="hljs-line">    ...
</div><div class="hljs-line">    plugins: [
</div><div class="hljs-line">        ...
</div><div class="hljs-line">        new MiniCssExtractPlugin({
</div><div class="hljs-line">            <span class="hljs-comment">// 设置编译后的文件名字</span>
</div><div class="hljs-line">            filename: <span class="hljs-string">'main.[hash].css'</span>
</div><div class="hljs-line">        })
</div><div class="hljs-line">    ],
</div><div class="hljs-line">    ...
</div><div class="hljs-line">    module: {
</div><div class="hljs-line">        <span class="hljs-attr">rules</span>: [{
</div><div class="hljs-line">            <span class="hljs-attr">test</span>: <span class="hljs-regexp">/\.(css|less)$/</span>,
</div><div class="hljs-line">            <span class="hljs-attr">use</span>: [
</div><div class="hljs-line">                <span class="hljs-comment">// 使用插件中的LOADER代替STYLE方式</span>
</div><div class="hljs-line">                MiniCssExtractPlugin.loader,
</div><div class="hljs-line">                ...
</div><div class="hljs-line">            ]
</div><div class="hljs-line">        }]
</div><div class="hljs-line">    }
</div><div class="hljs-line">};
</div></code></pre>

    <p><strong>基于babel实现ES6的转换</strong></p>

    <blockquote>
      <p>$ yarn add babel babel-loader @babel/preset-env @babel/core -D</p>

      <p>$ yarn add @babel/polyfill</p>
    </blockquote>



    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-built_in">module</span>.exports = {
</div><div class="hljs-line">    ...
</div><div class="hljs-line">    module: {
</div><div class="hljs-line">        <span class="hljs-attr">rules</span>: [{
</div><div class="hljs-line">            <span class="hljs-attr">test</span>: <span class="hljs-regexp">/\.js$/</span>,
</div><div class="hljs-line">            <span class="hljs-attr">use</span>: [<span class="hljs-string">'babel-loader'</span>],
</div><div class="hljs-line">            <span class="hljs-comment">// 设置编译时忽略的文件和指定编译目录</span>
</div><div class="hljs-line">            include: path.resolve(__dirname, <span class="hljs-string">'src'</span>),
</div><div class="hljs-line">            <span class="hljs-attr">exclude</span>: <span class="hljs-regexp">/node_modules/</span>
</div><div class="hljs-line">        }]
</div><div class="hljs-line">    }
</div><div class="hljs-line">};
</div></code></pre>

    <p>babel.config.js</p>

    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-built_in">module</span>.exports = {
</div><div class="hljs-line">    <span class="hljs-attr">presets</span>: [
</div><div class="hljs-line">        <span class="hljs-string">"@babel/preset-env"</span>
</div><div class="hljs-line">    ]
</div><div class="hljs-line">};
</div></code></pre>

    <p>index.js</p>



    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> <span class="hljs-string">'@babel/polyfill'</span>;
</div></code></pre>

    <p><strong>设置优化项：压缩CSS/JS</strong></p>

    <blockquote>
      <p>$ yarn add css-minimizer-webpack-plugin terser-webpack-plugin -D</p>
    </blockquote>

    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">const</span> TerserPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'terser-webpack-plugin'</span>);
</div><div class="hljs-line"><span class="hljs-keyword">const</span> CssMinimizerWebpackPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'css-minimizer-webpack-plugin'</span>);
</div><div class="hljs-line"><span class="hljs-built_in">module</span>.exports = {
</div><div class="hljs-line">    <span class="hljs-attr">optimization</span>: {
</div><div class="hljs-line">        <span class="hljs-comment">// 设置压缩方式</span>
</div><div class="hljs-line">        minimizer: [
</div><div class="hljs-line">            <span class="hljs-keyword">new</span> CssMinimizerWebpackPlugin(),
</div><div class="hljs-line">            <span class="hljs-keyword">new</span> TerserPlugin()
</div><div class="hljs-line">        ]
</div><div class="hljs-line">    }
</div><div class="hljs-line">};
</div></code></pre>

    <p><strong>设置解析器：配置别名</strong></p>



    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-built_in">module</span>.exports = {
</div><div class="hljs-line">    <span class="hljs-attr">resolve</span>: {
</div><div class="hljs-line">        <span class="hljs-attr">alias</span>: {
</div><div class="hljs-line">            <span class="hljs-string">'@'</span>: path.resolve(__dirname, <span class="hljs-string">'./src'</span>)
</div><div class="hljs-line">        }
</div><div class="hljs-line">    }
</div><div class="hljs-line">};
</div></code></pre>

    <p><strong>图片的处理</strong></p>

    <blockquote>
      <p>$ yarn add file-loader url-loader -D</p>
    </blockquote>



    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-built_in">module</span>.exports = {
</div><div class="hljs-line">    ...
</div><div class="hljs-line">    module: {
</div><div class="hljs-line">        <span class="hljs-attr">rules</span>: [
</div><div class="hljs-line">        ...
</div><div class="hljs-line">        {
</div><div class="hljs-line">            <span class="hljs-attr">test</span>: <span class="hljs-regexp">/\.(png|jpe?g|gif)$/i</span>,
</div><div class="hljs-line">            <span class="hljs-attr">type</span>: <span class="hljs-string">'javascript/auto'</span>,
</div><div class="hljs-line">            <span class="hljs-attr">use</span>: [{
</div><div class="hljs-line">                <span class="hljs-comment">// 把指定大小内的图片BASE64</span>
</div><div class="hljs-line">                loader: <span class="hljs-string">'url-loader'</span>,
</div><div class="hljs-line">                <span class="hljs-attr">options</span>: {
</div><div class="hljs-line">                    <span class="hljs-attr">limit</span>: <span class="hljs-number">200</span> * <span class="hljs-number">1024</span>,
</div><div class="hljs-line">                    <span class="hljs-attr">esModule</span>: <span class="hljs-literal">false</span>,
</div><div class="hljs-line">                    <span class="hljs-attr">name</span>: <span class="hljs-string">'images/[name].[hash].[ext]'</span>
</div><div class="hljs-line">                }
</div><div class="hljs-line">            }]
</div><div class="hljs-line">        }]
</div><div class="hljs-line">    },
</div><div class="hljs-line">    <span class="hljs-comment">// 设置打包的最大资源大小</span>
</div><div class="hljs-line">    performance: {
</div><div class="hljs-line">        <span class="hljs-attr">maxAssetSize</span>: <span class="hljs-number">100</span> * <span class="hljs-number">1024</span> * <span class="hljs-number">1024</span> * <span class="hljs-number">1024</span>,
</div><div class="hljs-line">        <span class="hljs-attr">maxEntrypointSize</span>: <span class="hljs-number">100</span> * <span class="hljs-number">1024</span> * <span class="hljs-number">1024</span> * <span class="hljs-number">1024</span>
</div><div class="hljs-line">    }
</div><div class="hljs-line">};
</div></code></pre>
  </div>
</body>

</html>